package com.cnsugar.common.mongodb;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.cnsugar.common.paging.Page;
import com.cnsugar.common.reflect.ReflectUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * @Description mongodb工具类
 * @Author Sugar
 * @Version 2017年1月10日 上午11:24:53
 * @Copyright cnsugar@163.com
 */
public class MongoSupport {
    private final static Logger log = LoggerFactory.getLogger(MongoSupport.class);
    public final static String ID = "_id";
    private final static Map<String, MongoCollection<Document>> collections = new HashMap<>();

    protected MongoDatabase db;

    public MongoSupport(MongoClient mongo, String dbname) {
        db = mongo.getDatabase(dbname);
        if (db == null) {
            throw new IllegalArgumentException("获取数据库实例失败：" + dbname);
        }
    }

    public MongoDatabase getDB() {
        return db;
    }

    public List<String> getCollectionNames() {
        List<String> list = new ArrayList<String>();
        MongoCursor<String> cursor = db.listCollectionNames().iterator();
        while (cursor.hasNext()) {
            list.add(cursor.next());
        }
        cursor.close();
        return list;
    }

    /**
     * 获取collection对象 - 指定Collection
     *
     * @param collectionName
     * @return
     */
    public MongoCollection<Document> getCollection(String collectionName) {
        MongoCollection<Document> coll = collections.get(collectionName);
        if (coll == null) {
            coll = db.getCollection(collectionName);
            collections.put(collectionName, coll);
        }
        return coll;
    }

    protected String getCollectionName(Class<?> clazz) {
        String collectionName = clazz.getSimpleName();
        Collection coll = clazz.getAnnotation(Collection.class);
        if (coll != null && coll.value() != null && !coll.value().isEmpty()) {
            collectionName = coll.value();
        }
        return collectionName;
    }

    public List<Document> findAll(String collectionName) {
        return find(collectionName, null, null, 0, 0);
    }

    public List<Document> findAll(String collectionName, Bson orderBy) {
        return find(collectionName, null, orderBy, 0, 0);
    }

    public List<Document> findAll(String collectionName, Bson orderBy, int limit) {
        return find(collectionName, null, orderBy, limit, 0);
    }

    public List<Document> findAll(String collectionName, int limit) {
        return find(collectionName, null, null, limit, 0);
    }

    public List<Document> findAll(String collectionName, int limit, int skip) {
        return find(collectionName, null, null, limit, skip);
    }

    /**
     * 查询所有数据列表, 返回Map结果集
     *
     * @param collectionName 集合名称
     * @param orderBy        排序, 如: new BasicDBObject("key", OrderBy.ASC)
     * @param limit          查询记录数(0-所有)
     * @param skip           跳过记录数
     * @return List<Map<String, Object>>
     */
    public List<Document> findAll(String collectionName, Bson orderBy, int limit, int skip) {
        return find(collectionName, null, orderBy, limit, skip);
    }

    public <T> List<T> findAll(Class<T> clazz) {
        String collectionName = getCollectionName(clazz);
        return find(clazz, collectionName, null, null, 0, 0);
    }

    public <T> List<T> findAll(Class<T> clazz, String collectionName) {
        return find(clazz, collectionName, null, null, 0, 0);
    }

    public <T> List<T> findAll(Class<T> clazz, String collectionName, Bson orderBy) {
        return find(clazz, collectionName, null, orderBy, 0, 0);
    }

    public <T> List<T> findAll(Class<T> clazz, String collectionName, Bson orderBy, int limit) {
        return find(clazz, collectionName, null, orderBy, limit, 0);
    }

    public <T> List<T> findAll(Class<T> clazz, String collectionName, int limit) {
        return find(clazz, collectionName, null, null, limit, 0);
    }

    public <T> List<T> findAll(Class<T> clazz, String collectionName, int limit, int skip) {
        return find(clazz, collectionName, null, null, limit, skip);
    }

    /**
     * 查询所有数据列表, 返回Java实体对象结果集
     *
     * @param clazz          Java实体对象, 如: User.class
     * @param collectionName 集合名称
     * @param orderBy        排序, 如: new BasicDBObject("key", OrderBy.ASC)
     * @param limit          查询记录数(0-所有)
     * @param skip           跳过记录数
     * @return List<T>
     */
    public <T> List<T> findAll(Class<T> clazz, String collectionName, Bson orderBy, int limit, int skip) {
        return find(clazz, collectionName, null, orderBy, limit, skip);
    }

    public List<Document> find(String collectionName, Bson filter) {
        return find(collectionName, filter, null, 0, 0);
    }

    public List<Document> find(String collectionName, Bson filter, Bson orderBy) {
        return find(collectionName, filter, orderBy, 0, 0);
    }

    public List<Document> find(String collectionName, Bson filter, Bson orderBy, int limit) {
        return find(collectionName, filter, orderBy, 0, 0);
    }

    public List<Document> find(String collectionName, Bson filter, int limit) {
        return find(collectionName, filter, null, 0, 0);
    }

    public List<Document> find(String collectionName, Bson filter, int limit, int skip) {
        return find(collectionName, filter, null, 0, 0);
    }

    /**
     * 查询数据列表, 返回Map结果集
     *
     * @param collectionName 集合名称
     * @param filter         查询条件, 如: Filters.eq("key", "value")
     * @param orderBy        排序, 如: new BasicDBObject("key", OrderBy.ASC)
     * @param limit          查询记录数(0-所有)
     * @param skip           跳过记录数
     * @return List<Map<String, Object>>
     */
    public List<Document> find(String collectionName, Bson filter, Bson orderBy, int limit, int skip) {
        // if (filter == null) {
        // filter = new BsonDocument();
        // }
        FindIterable<Document> find = null;
        // if (keys != null && keys.length > 0) {
        // Document _keys = new Document();
        // for(String key: keys) {
        // _keys.append(key, 1);
        // }
        // find = getCollection(collectionName).find(filter, _keys);
        // }
        if (filter == null) {
            find = getCollection(collectionName).find();
        } else {
            find = getCollection(collectionName).find(filter);
        }
        if (orderBy != null) {
            find.sort(orderBy);
        }
        if (skip > 0) {
            find.skip(skip);
        }
        if (limit > 0) {
            find.limit(limit);
        }
        MongoCursor<Document> cursor = find.iterator();
        List<Document> list = new ArrayList<>();
        try {
            while (cursor.hasNext()) {
                list.add(cursor.next());
            }
        } finally {
            cursor.close();
        }
        return list;
    }

    public <T> List<T> find(Class<T> clazz, Bson filter) {
        String collectionName = getCollectionName(clazz);
        return find(clazz, collectionName, filter, null, 0, 0);
    }

    public <T> List<T> find(Class<T> clazz, Bson filter, Bson orderBy) {
        String collectionName = getCollectionName(clazz);
        return find(clazz, collectionName, filter, orderBy, 0, 0);
    }

    public <T> List<T> find(Class<T> clazz, Bson filter, Bson orderBy, int limit) {
        String collectionName = getCollectionName(clazz);
        return find(clazz, collectionName, filter, orderBy, limit, 0);
    }

    public <T> List<T> find(Class<T> clazz, Bson filter, int limit) {
        String collectionName = getCollectionName(clazz);
        return find(clazz, collectionName, filter, null, limit, 0);
    }

    public <T> List<T> find(Class<T> clazz, Bson filter, int limit, int skip) {
        String collectionName = getCollectionName(clazz);
        return find(clazz, collectionName, filter, null, limit, skip);
    }

    public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter) {
        return find(clazz, collectionName, filter, null, 0, 0);
    }

    public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, Bson orderBy) {
        return find(clazz, collectionName, filter, orderBy, 0, 0);
    }

    public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, Bson orderBy, int limit) {
        return find(clazz, collectionName, filter, orderBy, limit, 0);
    }

    public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, int limit) {
        return find(clazz, collectionName, filter, null, limit, 0);
    }

    public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, int limit, int skip) {
        return find(clazz, collectionName, filter, null, limit, skip);
    }

    /**
     * 查询数据列表, 返回Java实体对象结果集
     *
     * @param clazz          Java实体对象, 如: User.class
     * @param collectionName 集合名称
     * @param filter         查询条件, 如: Filters.eq("key", "value")
     * @param orderBy        排序, 如: new BasicDBObject("key", OrderBy.ASC)
     * @param limit          查询记录数(0-所有)
     * @param skip           跳过记录数
     * @return List<T>
     */
    public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, Bson orderBy, int limit, int skip) {
        FindIterable<Document> find = null;
        if (filter == null) {
            find = getCollection(collectionName).find();
        } else {
            find = getCollection(collectionName).find(filter);
        }
        if (orderBy != null) {
            find.sort(orderBy);
        }
        if (skip > 0) {
            find.skip(skip);
        }
        if (limit > 0) {
            find.limit(limit);
        }
        MongoCursor<Document> cursor = find.iterator();
        List<T> list = new ArrayList<T>();
        try {
            while (cursor.hasNext()) {
                Document doc = cursor.next();
                ObjectId id = doc.getObjectId(ID);
                if (id != null) {// 将id的值转成hexString
                    doc.put(ID, id.toHexString());
                }
                String json = doc.toJson();
                list.add(JSONObject.parseObject(json, clazz));
            }
        } finally {
            cursor.close();
        }
        return list;
    }

    /**
     * 查询数据列表(去重), 返回Map结果集
     *
     * @param collectionName 集合名称
     * @param fieldName      要去重的字段
     * @param filter         查询条件, 如: Filters.eq("key", "value")
     * @return List<Map<String, Object>>
     */
    public List<Document> distinct(String collectionName, String fieldName, Bson filter) {
        DistinctIterable<Document> find = null;
        if (filter == null) {
            find = getCollection(collectionName).distinct(fieldName, Document.class);
        } else {
            find = getCollection(collectionName).distinct(fieldName, filter, Document.class);
        }
        MongoCursor<Document> cursor = find.iterator();
        List<Document> list = new ArrayList<>();
        try {
            while (cursor.hasNext()) {
                list.add(cursor.next());
            }
        } finally {
            cursor.close();
        }
        return list;
    }

    public Document findOne(String collectionName, Bson filter) {
        MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
        try {
            if (cursor.hasNext()) {
                return cursor.next();
            }
        } finally {
            cursor.close();
        }
        return null;
    }

    public <T> T findOne(Class<T> clazz, Bson filter) {
        String collectionName = getCollectionName(clazz);
        return findOne(clazz, collectionName, filter);
    }

    public <T> T findOne(Class<T> clazz, String collectionName, Bson filter) {
        MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
        try {
            if (cursor.hasNext()) {
                Document doc = cursor.next();
                ObjectId id = doc.getObjectId(ID);
                if (id != null) {// 将id的值转成hexString
                    doc.put(ID, id.toHexString());
                }
                String json = doc.toJson();
                return JSONObject.parseObject(json, clazz);
            }
        } finally {
            cursor.close();
        }
        return null;
    }

    public Page findPage(Page page) {
        String collectionName = getCollectionName(page.getClazz());
        return findPage(page, collectionName, null, null);
    }

    public Page findPage(Page page, String collectionName) {
        return findPage(page, collectionName, null, null);
    }

    public Page findPage(Page page, Bson filter) {
        String collectionName = getCollectionName(page.getClazz());
        return findPage(page, collectionName, filter, null);
    }

    public Page findPage(Page page, String collectionName, Bson filter) {
        return findPage(page, collectionName, filter, null);
    }

    public Page findPage(Page page, Bson filter, Bson orderBy) {
        String collectionName = getCollectionName(page.getClazz());
        return findPage(page, collectionName, filter, orderBy);
    }

    /**
     * 分页查询
     *
     * @param page           分页设置对象
     * @param collectionName 集合名称
     * @param filter         查询条件, 如: Filters.eq("key", "value")
     * @param orderBy        排序, 如: new BasicDBObject("key", OrderBy.ASC)
     * @return
     */
    public Page findPage(Page page, String collectionName, Bson filter, Bson orderBy) {
        if (page.getPageSize() <= 0) {
            page.reset();
            return page;
        }

        if (page.getTotalCount() == 0) {
            long total = count(collectionName, filter);
            if (total == 0) {
                page.reset();
                return page;
            }
            page.setTotalCount(total);
        }

        if (page.getPageNo() < 1) {
            page.setPageNo(1);
        } else if (page.getPageCount() > 0 && page.getPageNo() > page.getPageCount()) {
            page.setPageNo(page.getPageCount());
        }
        FindIterable<Document> find = null;
        if (filter == null) {
            find = getCollection(collectionName).find();
        } else {
            find = getCollection(collectionName).find(filter);
        }
        if (orderBy != null) {
            find.sort(orderBy);
        }
        find.skip((page.getPageNo() - 1) * page.getPageSize()).limit(page.getPageSize());
        MongoCursor<Document> cursor = find.iterator();
        List list = new ArrayList<>();
        try {
            boolean isDoc = page.getClazz().isAssignableFrom(Document.class);
            while (cursor.hasNext()) {
                Document doc = cursor.next();
                if (isDoc) {
                    list.add(doc);
                } else {
                    ObjectId id = doc.getObjectId(ID);
                    if (id != null) {// 将id的值转成hexString
                        doc.put(ID, id.toHexString());
                    }
                    String json = doc.toJson();
                    list.add(JSONObject.parseObject(json, page.getClazz()));
                }
            }
        } finally {
            cursor.close();
        }
        page.setList(list);

        if (page.getPageNo() == 1) {
            page.setPrevPageNo(0);
        } else {
            page.setPrevPageNo(page.getPageNo() - 1);
        }
        if (page.getPageNo() == page.getPageCount()) {
            page.setNextPageNo(0);
        } else {
            page.setNextPageNo(page.getPageNo() + 1);
        }
        return page;
    }

    public <T> T findById(Class<T> clazz, String id) {
        String collectionName = getCollectionName(clazz);
        return findById(clazz, collectionName, id);
    }

    public <T> T findById(Class<T> clazz, String collectionName, String id) {
        Bson filter = Filters.eq(ID, new ObjectId(id));
        MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
        try {
            if (cursor.hasNext()) {
                Document doc = cursor.next();
                ObjectId _id = doc.getObjectId(ID);
                if (_id != null) {// 将id的值转成hexString
                    doc.put(ID, _id.toHexString());
                }
                String json = doc.toJson();
                return JSONObject.parseObject(json, clazz);
            }
        } finally {
            cursor.close();
        }
        return null;
    }

    public Document findById(String collectionName, String id) {
        Bson filter = Filters.eq(ID, new ObjectId(id));
        MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
        try {
            if (cursor.hasNext()) {
                return cursor.next();
            }
        } finally {
            cursor.close();
        }
        return null;
    }

    public <T> long count(Class<T> clazz) {
        String collectionName = getCollectionName(clazz);
        return count(collectionName);
    }

    public long count(String collectionName) {
        return getCollection(collectionName).count();
    }

    public <T> long count(Class<T> clazz, Bson filter) {
        String collectionName = getCollectionName(clazz);
        return count(collectionName, filter);
    }

    public long count(String collectionName, Bson filter) {
        if (filter == null) {
            return getCollection(collectionName).count();
        }
        return getCollection(collectionName).count(filter);
    }

    public List<Document> count(String collectionName, String[] groupBy) {
        return count(collectionName, groupBy, null, 0);
    }

    public List<Document> count(String collectionName, String[] groupBy, Bson filter) {
        return count(collectionName, groupBy, filter, 0);
    }

    public List<Document> count(String collectionName, String[] groupBy, Bson filter, int limit) {
        StringBuilder mapFunction = new StringBuilder("function(){emit(");
        int len = groupBy.length;
        if (len == 1) {
            mapFunction.append("this.").append(groupBy[0]);
        } else {
            mapFunction.append("{");
            for (int i = 0; i < len; i++) {
                if (i > 0) {
                    mapFunction.append(",");
                }
                mapFunction.append(groupBy[i]).append(":this.").append(groupBy[i]);
            }
            mapFunction.append("}");
        }
        mapFunction.append(",1");
        mapFunction.append(");}");
        StringBuilder reduceFunction = new StringBuilder("function(key, values){");
        reduceFunction.append("var total = 0;");
        reduceFunction.append("values.forEach(function(val){total += val;});");
        reduceFunction.append("return total;");
        reduceFunction.append("}");
        MapReduceIterable<Document> find = getCollection(collectionName).mapReduce(mapFunction.toString(), reduceFunction.toString());
        if (filter != null) {
            find.filter(filter);
        }
        if (limit > 0) {
            find.limit(limit);
        }
        find.jsMode(true);
        MongoCursor<Document> cursor = find.iterator();
        List<Document> list = new ArrayList<Document>();
        try {
            while (cursor.hasNext()) {
                Document doc = cursor.next();
                if (len == 1) {
                    doc.put(groupBy[0], doc.get("_id"));
                } else {
                    doc.putAll((Document) doc.get("_id"));
                }
                doc.remove("_id");

				Object val = doc.get("value");
				if (val instanceof List) {
                    val = ((List) val).get(0);
				}
                long count = 0;
                if (val instanceof Number) {
                    count = ((Number)val).longValue();
                } else {
                    log.warn("{} is not a number!!! doc={}", val, doc);
                }
                doc.remove("value");
                doc.put("count", count);
                list.add(doc);
            }
        } finally {
            cursor.close();
        }
        return list;
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction) {
        return mapReduce(collectionName, mapFunction, reduceFunction, null, null, null, 0);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, Bson filter) {
        return mapReduce(collectionName, mapFunction, reduceFunction, null, filter, null, 0);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, Bson filter, Bson orderBy) {
        return mapReduce(collectionName, mapFunction, reduceFunction, null, filter, orderBy, 0);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, Bson filter, int limit) {
        return mapReduce(collectionName, mapFunction, reduceFunction, null, filter, null, limit);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction) {
        return mapReduce(collectionName, mapFunction, reduceFunction, finalizeFunction, null, null, 0);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter) {
        return mapReduce(collectionName, mapFunction, reduceFunction, finalizeFunction, filter, null, 0);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter, Bson orderBy) {
        return mapReduce(collectionName, mapFunction, reduceFunction, finalizeFunction, filter, orderBy, 0);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter, int limit) {
        return mapReduce(Document.class, collectionName, mapFunction, reduceFunction, finalizeFunction, filter, null, limit);
    }

    public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter, Bson orderBy, int
            limit) {
        return mapReduce(Document.class, collectionName, mapFunction, reduceFunction, finalizeFunction, filter, orderBy, limit);
    }

    public <T> List<T> mapReduce(Class<T> resultClass, String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson
            filter, int limit) {
        return mapReduce(resultClass, collectionName, mapFunction, reduceFunction, finalizeFunction, filter, null, limit);
    }

    public <T> List<T> mapReduce(Class<T> resultClass, String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson
            filter, Bson orderBy, int limit) {
        MapReduceIterable<T> find = getCollection(collectionName).mapReduce(mapFunction, reduceFunction, resultClass);
        if (filter != null) {
            find.filter(filter);
        }
        if (finalizeFunction != null && !finalizeFunction.isEmpty()) {
            find.finalizeFunction(finalizeFunction);
        }
        if (orderBy != null) {
            find.sort(orderBy);
        }
        if (limit > 0) {
            find.limit(limit);
        }
        find.jsMode(true);
        MongoCursor<T> cursor = find.iterator();
        List<T> list = new ArrayList<T>();
        try {
            while (cursor.hasNext()) {
                list.add(cursor.next());
            }
        } finally {
            cursor.close();
        }
        return list;
    }

    public void save(Object entity) {
        Class<?> clazz = entity.getClass();
        String collectionName = getCollectionName(clazz);
        save(entity, collectionName);
    }

    public void save(Object entity, String collectionName) {
        if (entity instanceof Document) {
            getCollection(collectionName).insertOne((Document) entity);
            if (log.isDebugEnabled()) {
                log.debug("Insert ok: " + entity);
            }
        } else if (entity instanceof Map) {
            getCollection(collectionName).insertOne(new Document((Map<String, Object>) entity));
            if (log.isDebugEnabled()) {
                log.debug("Insert ok: " + entity);
            }
        } else {
            String json = toJson(entity);
            getCollection(collectionName).insertOne(Document.parse(json));
            if (log.isDebugEnabled()) {
                log.debug("Insert ok: " + json);
            }
        }
    }

    public void saveAll(List<?> list) {
        Class<?> clazz = list.get(0).getClass();
        String collectionName = getCollectionName(clazz);
        saveAll(list, collectionName);
    }

    public void saveAll(List<?> list, String collectionName) {
        List<Document> docList = new ArrayList<Document>();
        for (Object obj : list) {
            if (obj instanceof Document) {
                docList.add((Document) obj);
            } else if (obj instanceof Map) {
                docList.add(new Document((Map<String, Object>) obj));
            } else {
                String json = toJson(obj);
                docList.add(Document.parse(json));
            }
        }
        getCollection(collectionName).insertMany(docList);
    }

    public <T> boolean update(T entity) {
        String collectionName = getCollectionName(entity.getClass());
        return update(entity, collectionName);
    }

    public <T> boolean update(T entity, String collectionName) {
        String id = null;
        String methodName = "getId";//默认id字估getter方法名
        try {
            id = (String) (entity.getClass().getMethod(methodName).invoke(entity));
        } catch (NoSuchMethodException ex) {
            List<Field> fields = ReflectUtils.getFields(entity.getClass());
            for (Field field : fields) {
                JSONField jf = field.getAnnotation(JSONField.class);
                if (jf != null && ID.equals(jf.name())) {
                    methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                    try {
                        id = (String) (entity.getClass().getMethod(methodName).invoke(entity));
                    } catch (IllegalAccessException| InvocationTargetException | NoSuchMethodException e) {
                        e.printStackTrace();
                        return false;
                    }
                    break;
                }
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            return false;
        }
        return updateById(entity, collectionName, id);
    }

    public <T> long update(T entity, Bson filter) {
        String collectionName = getCollectionName(entity.getClass());
        return update(entity, collectionName, filter, false);
    }

    public <T> long update(T entity, Bson filter, boolean mutil) {
        String collectionName = getCollectionName(entity.getClass());
        return update(entity, collectionName, filter, mutil);
    }

    public <T> long update(T entity, String collectionName, Bson filter, boolean mutil) {
        String json = toJson(entity);
        BasicDBObject update = BasicDBObject.parse(json);
        return update(collectionName, filter, new BasicDBObject("$set", update), mutil);
    }

    /**
     * 更新数据（updateOne）
     *
     * @param collectionName
     * @param filter
     * @param update
     * @return
     */
    public long update(String collectionName, Bson filter, Update update) {
        return update(collectionName, filter, update, false);
    }

    /**
     * 更新集合
     *
     * @param collectionName 集合名称
     * @param filter         更新条件，如：Filters.eq("key", "value")
     * @param update         更新字段
     *                       ，如：new Update().set("key", "value")
     * @param mutil          true-更新所有
     * @return
     */
    public long update(String collectionName, Bson filter, Update update, boolean mutil) {
        BasicDBObject _update = new BasicDBObject();
        if (!update.inc().isEmpty()) {
            _update.append("$inc", update.inc());
        }
        if (!update.set().isEmpty()) {
            _update.append("$set", update.set());
        }
        if (!update.unset().isEmpty()) {
            _update.append("$unset", update.unset());
        }
        return update(collectionName, filter, _update, mutil);
    }

    public long update(String collectionName, Bson filter, Bson update, boolean mutil) {
        UpdateResult result = null;
        if (mutil) {
            result = getCollection(collectionName).updateMany(filter, update);
        } else {
            result = getCollection(collectionName).updateOne(filter, update);
        }
        if (result.wasAcknowledged()) {
            return result.getModifiedCount();
        }
        return -1;
    }

    public <T> boolean updateById(T entity, String id) {
        String collectionName = getCollectionName(entity.getClass());
        return updateById(entity, collectionName, id);
    }

    public <T> boolean updateById(T entity, String collectionName, String id) {
        if (id == null || id.isEmpty()) {
            throw new IllegalArgumentException("id不能为空");
        }
        String json = toJson(entity);
        Bson filter = Filters.eq(ID, new ObjectId(id));
        BasicDBObject update = BasicDBObject.parse(json);
        UpdateResult result = getCollection(collectionName).updateOne(filter, new BasicDBObject("$set", update));
        if (result.wasAcknowledged()) {
            if (result.getModifiedCount() > 0) {
                return true;
            }
        } else {
            return true;
        }
        return false;
    }

    public boolean updateById(String collectionName, Update update, String id) {
        BasicDBObject _update = new BasicDBObject();
        if (!update.inc().isEmpty()) {
            _update.append("$inc", update.inc());
        }
        if (!update.set().isEmpty()) {
            _update.append("$set", update.set());
        }
        if (!update.unset().isEmpty()) {
            _update.append("$unset", update.unset());
        }
        return updateById(collectionName, _update, id);
    }

    public boolean updateById(String collectionName, Bson update, String id) {
        if (id == null || id.isEmpty()) {
            throw new IllegalArgumentException("id不能为空");
        }
        Bson filter = Filters.eq(ID, new ObjectId(id));
        UpdateResult result = getCollection(collectionName).updateOne(filter, update);
        if (result.wasAcknowledged()) {
            return (result.getModifiedCount() > 0);
        }
        return true;
    }

    public boolean deleteOne(String collectionName, Bson filter) {
        DeleteResult result = getCollection(collectionName).deleteOne(filter);
        if (result.wasAcknowledged()) {
            return (result.getDeletedCount() > 0);
        }
        return true;
    }

    public long deleteAll(String collectionName, Bson filter) {
        DeleteResult result = getCollection(collectionName).deleteMany(filter);
        if (result.wasAcknowledged()) {
            return result.getDeletedCount();
        }
        return 0;
    }

    public boolean deleteById(String collectionName, String id) {
        return deleteOne(collectionName, Filters.eq(ID, new ObjectId(id)));
    }

    public void drop(String collectionName) {
        getCollection(collectionName).drop();
    }

    public void createIndex(String collectionName, Bson keys) {
        getCollection(collectionName).createIndex(keys);
    }

    public void dropIndexes(String collectionName) {
        getCollection(collectionName).dropIndexes();
    }

    public void dropIndex(String collectionName, String indexName) {
        getCollection(collectionName).dropIndex(indexName);
    }

    protected String toJson(Object obj) {
        int features = 0;
        features |= SerializerFeature.QuoteFieldNames.getMask();
        features |= SerializerFeature.SkipTransientField.getMask();
        features |= SerializerFeature.WriteEnumUsingName.getMask();
        features |= SerializerFeature.SortField.getMask();
        features |= SerializerFeature.IgnoreNonFieldGetter.getMask();
        // features |= SerializerFeature.WriteMapNullValue.getMask();
        // features |= SerializerFeature.WriteNullBooleanAsFalse.getMask();
        // features |= SerializerFeature.WriteNullListAsEmpty.getMask();
        // features |= SerializerFeature.WriteNullNumberAsZero.getMask();
        // features |= SerializerFeature.WriteNullStringAsEmpty.getMask();
        return JSONObject.toJSONString(obj, features);
    }
}